{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# JupyterHub Spawners\n",
    "\n",
    "Let's peek at the base classes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from jupyterhub.spawner import Spawner, LocalProcessSpawner"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1;31mInit signature: \u001b[0m\u001b[0mSpawner\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mSource:\u001b[0m\n",
      "\u001b[1;32mclass\u001b[0m \u001b[0mSpawner\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mLoggingConfigurable\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;34m\"\"\"Base class for spawning single-user notebook servers.\u001b[0m\n",
      "\u001b[1;34m    \u001b[0m\n",
      "\u001b[1;34m    Subclass this, and override the following methods:\u001b[0m\n",
      "\u001b[1;34m    \u001b[0m\n",
      "\u001b[1;34m    - load_state\u001b[0m\n",
      "\u001b[1;34m    - get_state\u001b[0m\n",
      "\u001b[1;34m    - start\u001b[0m\n",
      "\u001b[1;34m    - stop\u001b[0m\n",
      "\u001b[1;34m    - poll\u001b[0m\n",
      "\u001b[1;34m    \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mdb\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAny\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0muser\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAny\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mhub\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAny\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mauthenticator\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAny\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mapi_token\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mUnicode\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mip\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mUnicode\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'127.0.0.1'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"The IP address (or hostname) the single-user server should listen on\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mstart_timeout\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m60\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"Timeout (in seconds) before giving up on the spawner.\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        This is the timeout for start to return, not the timeout for the server to respond.\u001b[0m\n",
      "\u001b[1;34m        Callers of spawner.start will assume that startup has failed if it takes longer than this.\u001b[0m\n",
      "\u001b[1;34m        start should return when the server process is started and its location is known.\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mhttp_timeout\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m30\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"Timeout (in seconds) before giving up on a spawned HTTP server\u001b[0m\n",
      "\u001b[1;34m\u001b[0m\n",
      "\u001b[1;34m        Once a server has successfully been spawned, this is the amount of time\u001b[0m\n",
      "\u001b[1;34m        we wait before assuming that the server is unable to accept\u001b[0m\n",
      "\u001b[1;34m        connections.\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mpoll_interval\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mInteger\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m30\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"Interval (in seconds) on which to poll the spawner.\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0m_callbacks\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mList\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0m_poll_callback\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAny\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mdebug\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mBool\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"Enable debug-logging of the single-user server\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0moptions_form\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mUnicode\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"\u001b[0m\n",
      "\u001b[1;34m        An HTML form for options a user can specify on launching their server.\u001b[0m\n",
      "\u001b[1;34m        The surrounding `<form>` element and the submit button are already provided.\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        For example:\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m            Set your key:\u001b[0m\n",
      "\u001b[1;34m            <input name=\"key\" val=\"default_key\"></input>\u001b[0m\n",
      "\u001b[1;34m            <br>\u001b[0m\n",
      "\u001b[1;34m            Choose a letter:\u001b[0m\n",
      "\u001b[1;34m            <select name=\"letter\" multiple=\"true\">\u001b[0m\n",
      "\u001b[1;34m              <option value=\"A\">The letter A</option>\u001b[0m\n",
      "\u001b[1;34m              <option value=\"B\">The letter B</option>\u001b[0m\n",
      "\u001b[1;34m            </select>\u001b[0m\n",
      "\u001b[1;34m    \"\"\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0moptions_from_form\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mform_data\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Interpret HTTP form data\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        Form data will always arrive as a dict of lists of strings.\u001b[0m\n",
      "\u001b[1;34m        Override this function to understand single-values, numbers, etc.\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        This should coerce form data into the structure expected by self.user_options,\u001b[0m\n",
      "\u001b[1;34m        which must be a dict.\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        Instances will receive this data on self.user_options, after passing through this function,\u001b[0m\n",
      "\u001b[1;34m        prior to `Spawner.start`.\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mreturn\u001b[0m \u001b[0mform_data\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0muser_options\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mDict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"This is where form-specified options ultimately end up.\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0menv_keep\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mList\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m'PATH'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m'PYTHONPATH'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m'CONDA_ROOT'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m'CONDA_DEFAULT_ENV'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m'VIRTUAL_ENV'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m'LANG'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m'LC_ALL'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"Whitelist of environment variables for the subprocess to inherit\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0menv\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mDict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"Deprecated: use Spawner.get_env or Spawner.environment\u001b[0m\n",
      "\u001b[1;34m    \u001b[0m\n",
      "\u001b[1;34m    - extend Spawner.get_env for adding required env in Spawner subclasses\u001b[0m\n",
      "\u001b[1;34m    - Spawner.environment for config-specified env\u001b[0m\n",
      "\u001b[1;34m    \"\"\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0menvironment\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mDict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"Environment variables to load for the Spawner.\u001b[0m\n",
      "\u001b[1;34m\u001b[0m\n",
      "\u001b[1;34m        Value could be a string or a callable. If it is a callable, it will\u001b[0m\n",
      "\u001b[1;34m        be called with one parameter, which will be the instance of the spawner\u001b[0m\n",
      "\u001b[1;34m        in use. It should quickly (without doing much blocking operations) return\u001b[0m\n",
      "\u001b[1;34m        a string that will be used as the value for the environment variable.\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mcmd\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mCommand\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'jupyterhub-singleuser'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"The command used for starting notebooks.\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0margs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mList\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mUnicode\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"Extra arguments to be passed to the single-user server\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mnotebook_dir\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mUnicode\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m''\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"The notebook directory for the single-user server\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        `~` will be expanded to the user's home directory\u001b[0m\n",
      "\u001b[1;34m        `%U` will be expanded to the user's username\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mdefault_url\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mUnicode\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m''\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"The default URL for the single-user server. \u001b[0m\n",
      "\u001b[1;34m\u001b[0m\n",
      "\u001b[1;34m        Can be used in conjunction with --notebook-dir=/ to enable \u001b[0m\n",
      "\u001b[1;34m        full filesystem traversal, while preserving user's homedir as\u001b[0m\n",
      "\u001b[1;34m        landing page for notebook\u001b[0m\n",
      "\u001b[1;34m\u001b[0m\n",
      "\u001b[1;34m        `%U` will be expanded to the user's username\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mdisable_user_config\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mBool\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mhelp\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m\"\"\"Disable per-user configuration of single-user servers.\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        This prevents any config in users' $HOME directories\u001b[0m\n",
      "\u001b[1;34m        from having an effect on their server.\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtag\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mconfig\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0msuper\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mSpawner\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstate\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mload_state\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstate\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mload_state\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstate\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"load state from the database\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        This is the extensible part of state\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        Override in a subclass if there is state to load.\u001b[0m\n",
      "\u001b[1;34m        Should call `super`.\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        See Also\u001b[0m\n",
      "\u001b[1;34m        --------\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        get_state, clear_state\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mpass\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mget_state\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"store the state necessary for load_state\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        A black box of extra state for custom spawners.\u001b[0m\n",
      "\u001b[1;34m        Subclasses should call `super`.\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        Returns\u001b[0m\n",
      "\u001b[1;34m        -------\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        state: dict\u001b[0m\n",
      "\u001b[1;34m             a JSONable dict of state\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mstate\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mreturn\u001b[0m \u001b[0mstate\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mclear_state\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"clear any state that should be cleared when the process stops\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        State that should be preserved across server instances should not be cleared.\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        Subclasses should call super, to ensure that state is properly cleared.\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mapi_token\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m''\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mget_env\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Return the environment dict to use for the Spawner.\u001b[0m\n",
      "\u001b[1;34m\u001b[0m\n",
      "\u001b[1;34m        This applies things like `env_keep`, anything defined in `Spawner.environment`,\u001b[0m\n",
      "\u001b[1;34m        and adds the API token to the env.\u001b[0m\n",
      "\u001b[1;34m\u001b[0m\n",
      "\u001b[1;34m        Use this to access the env in Spawner.start to allow extension in subclasses.\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0menv\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menv\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mwarnings\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwarn\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Spawner.env is deprecated, found %s\"\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menv\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mDeprecationWarning\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0menv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menv\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mfor\u001b[0m \u001b[0mkey\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menv_keep\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mif\u001b[0m \u001b[0mkey\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menviron\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0menv\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mos\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menviron\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;31m# config overrides. If the value is a callable, it will be called with\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;31m# one parameter - the current spawner instance - and the return value\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;31m# will be assigned to the environment variable. This will be called at\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;31m# spawn time.\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mfor\u001b[0m \u001b[0mkey\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0menvironment\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mitems\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mif\u001b[0m \u001b[0mcallable\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0menv\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0menv\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mkey\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0menv\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'JPY_API_TOKEN'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mapi_token\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mreturn\u001b[0m \u001b[0menv\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mget_args\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Return the arguments to be passed after self.cmd\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0margs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;34m'--user=%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;34m'--port=%i'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mserver\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mport\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;34m'--cookie-name=%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mserver\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcookie_name\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;34m'--base-url=%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mserver\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbase_url\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;34m'--hub-host=%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhub\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhost\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;34m'--hub-prefix=%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhub\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mserver\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbase_url\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;34m'--hub-api-url=%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhub\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mapi_url\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mip\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'--ip=%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mip\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnotebook_dir\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnotebook_dir\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnotebook_dir\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mreplace\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"%U\"\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'--notebook-dir=%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnotebook_dir\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdefault_url\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdefault_url\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdefault_url\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mreplace\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"%U\"\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'--NotebookApp.default_url=%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdefault_url\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdebug\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'--debug'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdisable_user_config\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'--disable-user-config'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mextend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mreturn\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m@\u001b[0m\u001b[0mgen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mstart\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Start the single-user process\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mraise\u001b[0m \u001b[0mNotImplementedError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Override in subclass. Must be a Tornado gen.coroutine.\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m@\u001b[0m\u001b[0mgen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mstop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnow\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mFalse\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Stop the single-user process\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mraise\u001b[0m \u001b[0mNotImplementedError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Override in subclass. Must be a Tornado gen.coroutine.\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m@\u001b[0m\u001b[0mgen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mpoll\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Check if the single-user process is running\u001b[0m\n",
      "\u001b[1;34m\u001b[0m\n",
      "\u001b[1;34m        return None if it is, an exit status (0 if unknown) if it is not.\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mraise\u001b[0m \u001b[0mNotImplementedError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Override in subclass. Must be a Tornado gen.coroutine.\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0madd_poll_callback\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcallback\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"add a callback to fire when the subprocess stops\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        as noticed by periodic poll_and_notify()\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0margs\u001b[0m \u001b[1;32mor\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mcb\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcallback\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mcallback\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mlambda\u001b[0m \u001b[1;33m:\u001b[0m \u001b[0mcb\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_callbacks\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcallback\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mstop_polling\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"stop the periodic poll\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_poll_callback\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_poll_callback\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_poll_callback\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mstart_polling\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Start polling periodically\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        callbacks registered via `add_poll_callback` will fire\u001b[0m\n",
      "\u001b[1;34m        if/when the process stops.\u001b[0m\n",
      "\u001b[1;34m        \u001b[0m\n",
      "\u001b[1;34m        Explicit termination via the stop method will not trigger the callbacks.\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpoll_interval\u001b[0m \u001b[1;33m<=\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdebug\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Not polling subprocess\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mreturn\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdebug\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Polling subprocess every %is\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpoll_interval\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstop_polling\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_poll_callback\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mPeriodicCallback\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpoll_and_notify\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;36m1e3\u001b[0m \u001b[1;33m*\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpoll_interval\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_poll_callback\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstart\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m@\u001b[0m\u001b[0mgen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mpoll_and_notify\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Used as a callback to periodically poll the process,\u001b[0m\n",
      "\u001b[1;34m        and notify any watchers\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mstatus\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32myield\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpoll\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mstatus\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;31m# still running, nothing to do here\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mreturn\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstop_polling\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mfor\u001b[0m \u001b[0mcallback\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_callbacks\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[1;32myield\u001b[0m \u001b[0mgen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmaybe_future\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcallback\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mexcept\u001b[0m \u001b[0mException\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexception\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Unhandled error in poll callback for %s\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mreturn\u001b[0m \u001b[0mstatus\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[0mdeath_interval\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mFloat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0.1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;33m@\u001b[0m\u001b[0mgen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mwait_for_death\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"wait for the process to die, up to timeout seconds\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtimeout\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdeath_interval\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mstatus\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32myield\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpoll\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mif\u001b[0m \u001b[0mstatus\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[1;32mbreak\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[1;32myield\u001b[0m \u001b[0mgen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdeath_interval\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\n",
      "\u001b[1;31mFile:           \u001b[0m~/conda/envs/jupyterhub-tutorial/lib/python3.5/site-packages/jupyterhub/spawner.py\n",
      "\u001b[1;31mType:           \u001b[0mMetaHasTraits\n"
     ]
    }
   ],
   "source": [
    "Spawner??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Start is the key method in a Spawner. It's how we decide how to start the process that will become the single-user server:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1;31mSignature: \u001b[0m\u001b[0mLocalProcessSpawner\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstart\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mSource:\u001b[0m\n",
      "    \u001b[1;33m@\u001b[0m\u001b[0mgen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mstart\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Start the process\"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mip\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mserver\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mip\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mip\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mserver\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mport\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mrandom_port\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mcmd\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0menv\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_env\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mcmd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mextend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcmd\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mcmd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mextend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_args\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Spawning %s\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m' '\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpipes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mquote\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ms\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0ms\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mcmd\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mproc\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mPopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcmd\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0menv\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0menv\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mpreexec_fn\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmake_preexec_fn\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mstart_new_session\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# don't forward signals\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpid\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mproc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpid\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\n",
      "\u001b[1;31mFile:      \u001b[0m~/conda/envs/jupyterhub-tutorial/lib/python3.5/site-packages/jupyterhub/spawner.py\n",
      "\u001b[1;31mType:      \u001b[0mfunction\n"
     ]
    }
   ],
   "source": [
    "LocalProcessSpawner.start??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is an example of a spawner that allows specifying extra *arguments* to pass to a user's notebook server, via `.options_form`. It results in a form like this:\n",
    "\n",
    "![form](img/spawn-form.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from traitlets import default\n",
    "\n",
    "class DemoFormSpawner(LocalProcessSpawner):\n",
    "    @default('options_form')\n",
    "    def _options_form(self):\n",
    "        default_env = \"YOURNAME=%s\\n\" % self.user.name\n",
    "        return \"\"\"\n",
    "        <label for=\"args\">Extra notebook CLI arguments</label>\n",
    "        <input name=\"args\" placeholder=\"e.g. --debug\"></input>\n",
    "        \"\"\".format(env=default_env)\n",
    "    \n",
    "    def options_from_form(self, formdata):\n",
    "        \"\"\"Turn html formdata (always lists of strings) into the dict we want.\"\"\"\n",
    "        options = {}\n",
    "        arg_s = formdata.get('args', [''])[0].strip()\n",
    "        if arg_s:\n",
    "            options['argv'] = shlex.split(arg_s)\n",
    "        return options\n",
    "    \n",
    "    def get_args(self):\n",
    "        \"\"\"Return arguments to pass to the notebook server\"\"\"\n",
    "        argv = super().get_args()\n",
    "        if self.user_options.get('argv'):\n",
    "            argv.extend(self.user_options['argv'])\n",
    "        return argv\n",
    "    \n",
    "    def get_env(self):\n",
    "        \"\"\"Return environment variable dict\"\"\"\n",
    "        env = super().get_env()\n",
    "        return env"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercise:\n",
    "\n",
    "Write a custom Spawner that allows users to specify *environment variables* to load into their server.\n",
    "\n",
    "\n",
    "-------"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from dockerspawner import DockerSpawner"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1;31mSignature: \u001b[0m\u001b[0mDockerSpawner\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstart\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mimage\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mextra_create_kwargs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mextra_start_kwargs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mextra_host_config\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mSource:\u001b[0m\n",
      "    \u001b[1;33m@\u001b[0m\u001b[0mgen\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m    \u001b[1;32mdef\u001b[0m \u001b[0mstart\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mimage\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mextra_create_kwargs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mextra_start_kwargs\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mextra_host_config\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mNone\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;34m\"\"\"Start the single-user server in a docker container. You can override\u001b[0m\n",
      "\u001b[1;34m        the default parameters passed to `create_container` through the\u001b[0m\n",
      "\u001b[1;34m        `extra_create_kwargs` dictionary and passed to `start` through the\u001b[0m\n",
      "\u001b[1;34m        `extra_start_kwargs` dictionary.  You can also override the\u001b[0m\n",
      "\u001b[1;34m        'host_config' parameter passed to `create_container` through the\u001b[0m\n",
      "\u001b[1;34m        `extra_host_config` dictionary.\u001b[0m\n",
      "\u001b[1;34m\u001b[0m\n",
      "\u001b[1;34m        Per-instance `extra_create_kwargs`, `extra_start_kwargs`, and\u001b[0m\n",
      "\u001b[1;34m        `extra_host_config` take precedence over their global counterparts.\u001b[0m\n",
      "\u001b[1;34m\u001b[0m\n",
      "\u001b[1;34m        \"\"\"\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mcontainer\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32myield\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_container\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mcontainer\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mimage\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mimage\u001b[0m \u001b[1;32mor\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_image\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;31m# build the dictionary of keyword arguments for create_container\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mcreate_kwargs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0mimage\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mimage\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0menvironment\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_env\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0mvolumes\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvolume_mount_points\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0mname\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_name\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mcreate_kwargs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mextra_create_kwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mif\u001b[0m \u001b[0mextra_create_kwargs\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0mcreate_kwargs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mextra_create_kwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;31m# build the dictionary of keyword arguments for host_config\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mhost_config\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbinds\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvolume_binds\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlinks\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlinks\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muse_internal_ip\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0mhost_config\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'port_bindings'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;36m8888\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_ip\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mhost_config\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mextra_host_config\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;32mif\u001b[0m \u001b[0mextra_host_config\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0mhost_config\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mextra_host_config\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdebug\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Starting host with config: %s\"\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mhost_config\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mhost_config\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mclient\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcreate_host_config\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m**\u001b[0m\u001b[0mhost_config\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mcreate_kwargs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msetdefault\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'host_config'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mhost_config\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;31m# create the container\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mresp\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32myield\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdocker\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'create_container'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mcreate_kwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_id\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mresp\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'Id'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[1;34m\"Created container '%s' (id: %s) from image %s\"\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_id\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mimage\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[1;34m\"Found existing container '%s' (id: %s)\"\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m                \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_id\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;31m# TODO: handle unpause\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[1;34m\"Starting container '%s' (id: %s)\"\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_id\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m7\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;31m# build the dictionary of keyword arguments for start\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mstart_kwargs\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mstart_kwargs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mextra_start_kwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32mif\u001b[0m \u001b[0mextra_start_kwargs\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m            \u001b[0mstart_kwargs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mextra_start_kwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;31m# start the container\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[1;32myield\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdocker\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'start'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcontainer_id\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mstart_kwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mip\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mport\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32myield\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_ip_and_port\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mserver\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mip\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mip\u001b[0m\u001b[1;33m\u001b[0m\n",
      "\u001b[1;33m\u001b[0m        \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0muser\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mserver\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mport\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mport\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\n",
      "\u001b[1;31mFile:      \u001b[0m~/conda/envs/jupyterhub-tutorial/lib/python3.5/site-packages/dockerspawner/dockerspawner.py\n",
      "\u001b[1;31mType:      \u001b[0mfunction\n"
     ]
    }
   ],
   "source": [
    "DockerSpawner.start??"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercise:\n",
    "\n",
    "Subclass DockerSpawner so that users can specify via `options_form` what docker image to use.\n",
    "\n",
    "Candidates from the [Jupyter docker-stacks repo](https://github.com/jupyter/docker-stacks) include:\n",
    "\n",
    "- jupyter/minimal-singleuser\n",
    "- jupyter/scipy-singleuser\n",
    "- jupyter/r-singleuser\n",
    "- jupyter/datascience-singleuser\n",
    "- jupyter/pyspark-singleuser\n",
    "\n",
    "Or, build your own images with\n",
    "\n",
    "    FROM jupyterhub/singleuser\n",
    "    \n",
    "The easiest version will assume that the images are fetched already."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Extra credit:\n",
    "\n",
    "Subclass DockerSpawner so that users can specify via `options_form` a GitHub repository to clone and install, a la [binder](http://mybinder.org)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
